﻿using LT_Kernel;
using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using UnityWebSocket;

namespace NET
{
    /// <summary>
    /// WebSocket管理器
    /// </summary>
    public abstract class AbsWebSocketMgr : AbsMgr
    {
        private WebSocket m_Socket;

        public WebSocketState State
        {
            get
            {
                return m_Socket == null ? WebSocketState.Closed : m_Socket.ReadyState;
            }
        }

        public void Connect(string host)
        {
            if (State == WebSocketState.Closed)
            {
                //自己补充请求头
                Dictionary<string, string> tmp = new Dictionary<string, string>();
                string Timee = $"{(DateTime.Now.ToUniversalTime().Ticks - 621355968000000000) / 10000000}";
                string noncestr = GetRandomCharacters(6);
                string secret = "WS\n" + GameConst.AppID + "\n" + GameConst.Platform + "\n" + Timee + "\n" + noncestr + "\n" + GameConst.appSecret;
                tmp.Add("gameid", GameConst.AppID);
                tmp.Add("platform", GameConst.Platform);
                tmp.Add("timestamp", Timee);
                tmp.Add("noncestr", noncestr);
                tmp.Add("signature", HmacSHA256(secret));

                m_Socket = new WebSocket(host, tmp);
                m_Socket.OnOpen += OnOpen;
                m_Socket.OnMessage += OnMsg;
                m_Socket.OnClose += OnClose;
                m_Socket.OnError += OnError;
                m_Socket.ConnectAsync();
                LTLog.W("WebSocket on connecting...");
            }
        }

        public string HmacSHA256(string message)
        {
            byte[] keyByte = Encoding.GetEncoding("utf-8").GetBytes(GameConst.appSecret);
            byte[] messageBytes = Encoding.GetEncoding("utf-8").GetBytes(message);
            using (var hmacsha256 = new HMACSHA256(keyByte))
            {
                byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
                return Convert.ToBase64String(hashmessage);
            }
        }

        /// <summary>
        /// v生成随机字母字符串(数字字母混和)
        /// </summary>
        /// <param name="n"></param>
        /// <param name="Number"></param>
        /// <param name="Lowercase"></param>
        /// <param name="Capital"></param>
        /// <returns></returns>
        public static string GetRandomCharacters(int n = 10, bool Number = true, bool Lowercase = false, bool Capital = false)
        {
            StringBuilder tmp = new StringBuilder();
            Random rand = new Random();
            string characters = (Capital ? "ABCDEFGHIJKLMNOPQRSTUVWXYZ" : null) + (Number ? "0123456789" : null) + (Lowercase ? "abcdefghijklmnopqrstuvwxyz" : null);
            if (characters.Length < 1)
            {
                return (null);
            }
            for (int i = 0; i < n; i++)
            {
                tmp.Append(characters[rand.Next(0, characters.Length)].ToString());
            }
            return (tmp.ToString());
        }

        public void Disconnect()
        {
            LTLog.L("Disconnect...");
            m_Socket?.CloseAsync();
            m_Socket = null;

        }

        protected void SendMsg(byte[] datas)
        {
            m_Socket?.SendAsync(datas);
        }

        private void OnError(object sender, ErrorEventArgs e)
        {
            LTLog.E($"WebSocket错误\t原因:{e.Message}");
            OnErrorHandle(sender, e);
        }

        private void OnClose(object sender, CloseEventArgs e)
        {
            LTLog.W($"WebSocket关闭连接\tcode:{e.Code}\t原因:{e.Reason}");
            OnCloseHandle(sender, e);
        }

        private void OnMsg(object sender, MessageEventArgs e)
        {
            OnMsgHandle(sender, e);
        }

        private void OnOpen(object sender, OpenEventArgs e)
        {
            LTLog.W("连接成功!!!");
            OnOpenHandle(sender, e);
        }

        public abstract void OnErrorHandle(object sender, ErrorEventArgs e);

        public abstract void OnCloseHandle(object sender, CloseEventArgs e);

        public abstract void OnMsgHandle(object sender, MessageEventArgs e);

        public abstract void OnOpenHandle(object sender, OpenEventArgs e);
    }
}